/********************************************************/
/*	Copyright (C) 2016 Gong Li Bin		 	*/
/*	Project:	GlbLib-1.0.0			*/
/*	Author:		gong_libin			*/
/*	Date:		2016_06_01			*/
/*	File:		GlbTcp.cpp			*/
/********************************************************/

#include "GlbTcp.h"

namespace GlbNet
{

CGlbTcp::CGlbTcp()
{
	m_pFunction = NULL;
}

CGlbTcp::~CGlbTcp()
{
	m_pFunction = NULL;
}

void CGlbTcp::GlbTcpAccept()
{
	int iNewSocket = 0;
	socklen_t iClientSize = 0;
	struct sockaddr_in stClient;

	iClientSize = (socklen_t)sizeof(struct sockaddr_in);
	while (true) {
		iNewSocket = accept(CGlbNet::m_iSocket, (struct sockaddr*)&stClient, &iClientSize);
		if (iNewSocket > 0) {
			(*m_pFunction)(iNewSocket);
		}
	}

	return;
}

void CGlbTcp::GlbTcpSetFunction(void (*pFunction)(int))
{
	m_pFunction = pFunction;

	return;
}

int CGlbTcp::GlbTcpSetNoDelay()
{
	int iOn = 1;

	if (GLB_FAILURE == setsockopt(CGlbNet::m_iSocket, IPPROTO_TCP, TCP_NODELAY, &iOn, sizeof(iOn))) {
		GLB_ERROR("%s\n", strerror(errno));
		return GLB_FAILURE;
	}

	return GLB_SUCCESS;
}

void CGlbTcp::GlbTcpShutdown(int iHow)
{
	shutdown(CGlbNet::m_iSocket, iHow);

	return;
}

int CGlbTcp::GlbTcpSetLinger(int iSecond)
{
	struct linger stLinger;

	stLinger.l_onoff = 1;
	stLinger.l_linger = iSecond;

	if (GLB_FAILURE == setsockopt(CGlbNet::m_iSocket, SOL_SOCKET, SO_LINGER, (char*)&stLinger, sizeof(struct linger))) {
		GLB_ERROR("%s\n", strerror(errno));
		return GLB_FAILURE;
	}

	return GLB_SUCCESS;
}

int CGlbTcp::GlbTcpInit(char* pszPort)
{
	struct sockaddr_in stServer;

	memset(&stServer, '\0', sizeof(struct sockaddr_in));
	stServer.sin_addr.s_addr = htonl(INADDR_ANY);
	stServer.sin_port = htons(atoi(pszPort));
	stServer.sin_family = AF_INET;

	if (GLB_SUCCESS != CGlbNet::GlbNetOpen(GLB_AF_INET, GLB_SOCK_STREAM)) {
		return GLB_FAILURE;
	}

	if (GLB_SUCCESS != GlbNetBind(&stServer)) {
		GLB_ERROR("%s\n", strerror(errno));
		CGlbNet::GlbNetClose();
		return GLB_FAILURE;
	}

	if (listen(CGlbNet::m_iSocket, GLB_LISTEN) < 0) {
		GLB_ERROR("%s\n", strerror(errno));
		CGlbNet::GlbNetClose();
		return GLB_FAILURE;
	}

	return GLB_SUCCESS;
}

int CGlbTcp::GlbTcpConnect(char* pszUrl)
{
	char* pszPort = NULL;
	int iReturn = GLB_SUCCESS;

	if (NULL != (pszPort = CGlbNet::GlbNetUrl(pszUrl))) {
		iReturn = GlbTcpConnect(pszUrl, pszPort);
	}
	else {
		iReturn = GLB_FAILURE;
	}

	return iReturn;
}

int CGlbTcp::GlbTcpConnect(struct sockaddr_in* pstAddr)
{
	int iReturn = GLB_SUCCESS;

	if (GLB_SUCCESS == CGlbNet::GlbNetOpen(GLB_AF_INET, GLB_SOCK_STREAM)) {
		CGlbNet::GlbNetSetTimeOut(GLB_TIMEOUT, 0);
		if (connect(CGlbNet::m_iSocket, (struct sockaddr*)pstAddr, sizeof(struct sockaddr_in)) < 0) {
			GLB_ERROR("%s\n", strerror(errno));
			iReturn = GLB_FAILURE;
			CGlbNet::GlbNetClose();
		}
	}
	else {
		iReturn = GLB_FAILURE;
	}

	return iReturn;
}

int CGlbTcp::GlbTcpConnect(char* pszAddress, char* pszPort)
{
	int iReturn = GLB_SUCCESS;
	struct sockaddr_in stAddr;

	memset(&stAddr, '\0', sizeof(struct sockaddr_in));
	stAddr.sin_addr.s_addr = inet_addr(pszAddress);
	stAddr.sin_port = htons(atoi(pszPort));
	stAddr.sin_family = AF_INET;

	if (GLB_SUCCESS == CGlbNet::GlbNetOpen(GLB_AF_INET, GLB_SOCK_STREAM)) {
		CGlbNet::GlbNetSetTimeOut(GLB_TIMEOUT, 0);
		if (connect(CGlbNet::m_iSocket, (struct sockaddr*)&stAddr, sizeof(struct sockaddr_in)) < 0) {
			GLB_ERROR("%s\n", strerror(errno));
			iReturn = GLB_FAILURE;
			CGlbNet::GlbNetClose();
		}
	}
	else {
		iReturn = GLB_FAILURE;
	}

	return iReturn;
}

int CGlbTcp::GlbNetSendAll(UCHAR* puszPacket, int iLength)
{
	int iCount = 0;
	int iTotal = 0;

	while (iTotal < iLength) {
		if ((iCount = GlbNetSend(puszPacket + iTotal, iLength - iTotal)) > 0) {
			iTotal += iCount;
		}
		else {
			GLB_ERROR("%s\n", strerror(errno));
			break;
		}
	}

	return iTotal;

}

int CGlbTcp::GlbNetRecvAll(UCHAR* puszPacket, int iLength)
{
	int iCount = 0;
	int iTotal = 0;

	while (iTotal < iLength) {
		if ((iCount = GlbNetRecv(puszPacket + iTotal, iLength - iTotal)) > 0) {
			iTotal += iCount;
		}
		else {
			GLB_ERROR("%s\n", strerror(errno));
			break;
		}
	}

	return iTotal;

}

} /* GlbNet */
